<!DOCTYPE html>
<style>
host {
  border: solid 1px red;
  padding: 5px;
}
.sample{
  border: solid 1px green;
  padding: 10px;
}
</style>
<div>
<div id="sample1" class="sample">012<div id="host1">host1</div>345</div>
<div id="sample2" class="sample" contenteditable>012<div id="host2">host2</div>345</div>
<div id="sample3" class="sample">012<div id="host3">host3abc<div id="host4">host4</div>host3def</div>345</div>
<div id="sample4" class="sample">012<div id="host5">host5</div>345</div>
</div>
<p>end of document</p>
<script src="../../resources/js-test.js"></script>
<script>
description('SelectAll and Shadow DOM Tree');

function installShadowTree(host) {
    var shadowRoot = host.attachShadow({mode: 'open'});
    shadowRoot.innerHTML = '<i>BEFORE</i> <b><slot></b> <i>AFTER</i>';
}

var selection = window.getSelection();

// In this file, we use following symbols in pictures in comment.
// ^=anchor position, |=focus position, [...]=shadow DOM boundary.

debug('Select all from host content in shadow tree => select all on document');
// before 012 [BEFORE ^host1| AFTER] 345
// select all
// after ^... 012 [^BEFORE host1 AFTER] 345 ...|
var host1 = document.getElementById('host1');
installShadowTree(host1);
selection.collapse(host1, 0);
document.execCommand('selectAll');
shouldBeEqualToString('selection.anchorNode.nodeValue', 'SelectAll and Shadow DOM Tree');
shouldBe('selection.anchorOffset', '0');
shouldBeEqualToString('selection.focusNode.nodeValue', 'end of document');
shouldBe('selection.focusOffset', '15');

debug('\nSelect all from "EFO" in shadow tree => select descendants of immediate child of shadow root containing start position');
// before 012 [B^EFO|RE host1 AFTER] 345
// select all
// after 012 [^BEFORE| host2 AFTER] 345
selection.collapse(host1.shadowRoot.firstChild.firstChild, 1);
selection.extend(host1.shadowRoot.firstChild.firstChild, 4);
document.execCommand('selectAll');
shouldBe('selection.anchorNode', 'host1.parentNode');
shouldBe('selection.anchorOffset', '1');
shouldBe('selection.focusNode', 'host1.parentNode');
shouldBe('selection.focusOffset', '1');
var selectionInHost1 = host1.shadowRoot.getSelection();
shouldBeEqualToString('selectionInHost1.anchorNode.nodeValue', 'BEFORE');
shouldBe('selectionInHost1.anchorOffset', '0');
shouldBeEqualToString('selectionInHost1.focusNode.nodeValue', 'BEFORE');
shouldBe('selectionInHost1.focusOffset', '6');

debug('\nSelect all from host content in editable => select all in editable rather than whole document');
// before 012 [BEFORE |host2 AFTER] 345
// select all
// after ^012 [BEFORE host2 AFTER] 345|
var host2 = document.getElementById('host2');
installShadowTree(host2);
selection.collapse(host2, 0);
document.execCommand('selectAll');
shouldBeEqualToString('selection.anchorNode.nodeValue', '012');
shouldBe('selection.anchorOffset', '0');
shouldBeEqualToString('selection.focusNode.nodeValue', '345');
shouldBe('selection.anchorOffset', '0');

debug('\nSelect all from "EFO" in shadow tree => select descendants of immediate child of shadow root containing start position, host editable doesn\'t affect select all');
// before 012 [B^EFO|RE host2 AFTER] 345
// select all
// after 012 [^BEFORE| host2 AFTER] 345
selection.collapse(host2.shadowRoot.firstChild.firstChild, 1);
selection.extend(host2.shadowRoot.firstChild.firstChild, 4);
document.execCommand('selectAll');
shouldBe('selection.anchorNode', 'host2.parentNode');
shouldBe('selection.anchorOffset', '1');
shouldBe('selection.focusNode', 'host2.parentNode');
shouldBe('selection.focusOffset', '1');
var selectionInHost2 = host2.shadowRoot.getSelection();
shouldBeEqualToString('selectionInHost2.anchorNode.nodeValue', 'BEFORE');
shouldBe('selectionInHost2.anchorOffset', '0');
shouldBeEqualToString('selectionInHost2.focusNode.nodeValue', 'BEFORE');
shouldBe('selectionInHost2.focusOffset', '6');

debug('\nSelect all from host content in nested shadow tree => select all on document');
// before 012 [BEFORE host3abc[BFORE |host4 AFTER] host3def AFTER] 345
// select all
// after ^ ... 012 [BEFORE host3abc[BEFORE host4 AFTER] host3def AFTER] 345 ... |
var host3 = document.getElementById('host3');
installShadowTree(host3);
var host4 = document.getElementById('host4');
installShadowTree(host4);
selection.collapse(host4, 0);
document.execCommand('selectAll');
shouldBeEqualToString('selection.anchorNode.nodeValue', 'SelectAll and Shadow DOM Tree');
shouldBe('selection.anchorOffset', '0');
shouldBeEqualToString('selection.focusNode.nodeValue', 'end of document');
shouldBe('selection.focusOffset', '15');

debug('\nSelect all from "EFO" in nested shadow tree => select descendants of immediate child of shadow root containing start position');
// before 012 [BEFORE host3abc[B^EFO|RE host4 AFTER] host3def AFTER] 345
// select all
// after 012 [BEFORE host3abc[^BEFORE| host4 AFTER] host3def AFTER] 345
selection.collapse(host4.shadowRoot.firstChild.firstChild, 1);
selection.extend(host4.shadowRoot.firstChild.firstChild, 4);
document.execCommand('selectAll');
shouldBe('selection.anchorNode', 'host4.parentNode');
shouldBe('selection.anchorOffset', '1');
shouldBe('selection.focusNode', 'host4.parentNode');
shouldBe('selection.focusOffset', '1');

var selectionInHost3 = host3.shadowRoot.getSelection();
shouldBe('selectionInHost3.anchorNode', 'null');
shouldBe('selectionInHost3.anchorOffset', '0');
shouldBe('selectionInHost3.focusNode', 'null');
shouldBe('selectionInHost3.focusOffset', '0');

var selectionInHost4 = host4.shadowRoot.getSelection();
shouldBeEqualToString('selectionInHost4.anchorNode.nodeValue', 'BEFORE');
shouldBe('selectionInHost4.anchorOffset', '0');
shouldBeEqualToString('selectionInHost4.focusNode.nodeValue', 'BEFORE');
shouldBe('selectionInHost4.focusOffset', '6');
</script>
